function parse3Attributes(names, args) {

    var res = {};

    if (args.length > 2) {
        res[names[1]] = args[2];
        res[names[0]] = args[1];
        res['message'] = args[0];
    } else {
        res[names[1]] = args[1];
        res[names[0]] = args[0];
        res['message'] = '';
    }

    return res;

}

function parse2Attributes(names, args) {

    var res = {};

    if (args.length > 1) {
        res[names[0]] = args[1];
        res['message'] = args[0];
    } else {
        res[names[0]] = args[0];
        res['message'] = '';
    }

    return res;

}

function assertEquals(message, expected, actual) {
    var args = parse3Attributes(['expected', 'actual'], arguments);
    deepEqual(args.actual, args.expected, args.message);
}

function assertNotEquals(message, expected, actual) {
    var args = parse3Attributes(['expected', 'actual'], arguments);
    notDeepEqual(args.actual, args.expected, args.message);
}

function assertSame(message, expected, actual) {
    var args = parse3Attributes(['expected', 'actual'], arguments);
    equal(args.actual, args.expected, args.message);
}
function assertNotSame(message, expected, actual) {
    var args = parse3Attributes(['expected', 'actual'], arguments);
    notEqual(args.actual, args.expected, args.message);
}

function assertTrue(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertEquals(args.message, args.actual, true);
}

function assertFalse(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertEquals(args.message, args.actual, false);
}

function assertNull(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertEquals(args.message, args.actual, null);
}

function assertNotNull(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertNotEquals(args.message, args.actual, null);
}

function assertUndefined(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertEquals(args.message, args.actual, undefined);
}

function assertNotUndefined(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertNotEquals(args.message, args.actual, undefined);
}

function assertNaN(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertTrue(args.message, isNaN(actual));
}

function assertNotNaN(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertFalse(args.message, isNaN(actual));
}

function assertInstanceOf(message, constructor, actual) {
    var args = parse3Attributes(['constructor', 'actual'], arguments);
    equal(args.actual instanceof args.constructor, true, args.message);
}

function assertNotInstanceOf(message, constructor, actual) {
    var args = parse3Attributes(['constructor', 'actual'], arguments);
    notEqual(args.actual instanceof args.constructor, true, args.message);
}

function assertTypeOf(message, expected, value) {
    var args = parse3Attributes(['expected', 'value'], arguments);
    equal(typeof args.value, args.expected, args.message);
}

function assertArray(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertTypeOf(args.message, 'array', args.actual);
}

function assertBoolean(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertTypeOf(args.message, 'boolean', args.actual);
}

function assertObject(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertTypeOf(args.message, 'object', args.actual);
}

function assertNumber(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertTypeOf(args.message, 'number', args.actual);
}

function assertString(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertTypeOf(args.message, 'string', args.actual);
}

function assertFunction(message, actual) {
    var args = parse2Attributes(['actual'], arguments);
    assertTypeOf(args.message, 'function', args.actual);
}

function assertException(message, callback, error) {
    var args = parse2Attributes(['callback', 'error'], arguments);
    //if (!args.error) args.error = function(){return true};
    raises(args.callback, args.error, args.message);
}

function assertNoException(message, callback) {
    var args = parse2Attributes(['callback'], arguments);
    try {
        args.callback();
        ok(true, args.message);
    } catch (e) {
        ok(false, e.message);
    }
}

function fail(message) {
    ok(false, message);
}

function TestCase(name, options) {

    function forEach(object, callback) {

        for (var i in object) {
            if (({}).hasOwnProperty.call(object, i)) {
                callback(object[i], i);
            }
        }

    }

    module(name, {
        setup: function(){
            if ('setUp' in options) options.setUp.call(options);
        },
        teardown: function(){
            if ('tearDown' in options) options.tearDown.call(options);
        }
    });

    forEach(options, function(method, key) {

        if (typeof method !== 'function') return;
        if (key.substr(0, 4) != 'test') return;

        asyncTest(key, function() {
            method.call(options);
            start();
        });

    });

};